package org.kl.bf.web.workflow;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.form.TaskFormDataImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.kl.bf.entity.easyui.EasyuiGrid;
import org.kl.bf.entity.workflow.EProcessInstance;
import org.kl.bf.entity.workflow.ETask;
import org.kl.bf.utils.ProcessDefinitionCache;
import org.kl.bf.web.base.BasicController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springside.modules.mapper.BeanMapper;
import org.springside.modules.utils.Collections3;
import org.springside.modules.web.MediaTypes;

@Controller
@RequestMapping(value = "/workflow/activitiProcessInstance")
public class ActivitiProcessInstanceController extends BasicController {
	private Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private TaskService taskService;
	@Autowired
	private FormService formService;
	@Autowired
	private IdentityService identityService;
	@Autowired
	private HistoryService historyService;

	protected static Map<String, ProcessDefinition> PROCESS_DEFINITION_CACHE = new HashMap<String, ProcessDefinition>();

	/**
	 * 挂起、激活流程实例
	 */
	@RequestMapping(value = "update/{state}/{processInstanceId}")
	@ResponseBody
	public String updateState(@PathVariable("state") String state, @PathVariable("processInstanceId") String processInstanceId,
			RedirectAttributes redirectAttributes) {
		if (state.equals("active")) {
			runtimeService.activateProcessInstanceById(processInstanceId);
			return ajaxMsg("已激活ID为[" + processInstanceId + "]的流程实例。", true, null);
		} else if (state.equals("suspend")) {
			runtimeService.suspendProcessInstanceById(processInstanceId);
			return ajaxMsg("已挂起ID为[" + processInstanceId + "]的流程实例。", true, null);
		}
		return ajaxMsg("操作动作指令无效", false, null);
	}

	@RequestMapping(value = "running/list", method = RequestMethod.GET)
	public String running() {
		return "workflow/activitiProcessInstanceList";
	}

	/**
	 * 运行中的流程
	 * 
	 * @param pageNumber
	 * @param pageSize
	 * @param sortType
	 * @param orderType
	 * @param model
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "running/dataGrid", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String dataGrid(@RequestParam(value = "pageNumber", defaultValue = "1") int pageNumber,
			@RequestParam(value = "rows", defaultValue = PAGE_SIZE) int pageSize,
			@RequestParam(value = "sort", defaultValue = "id") String sortType,
			@RequestParam(value = "order", defaultValue = "desc") String orderType, org.springframework.ui.Model model,
			ServletRequest request) {
		ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
		List<ProcessInstance> list = processInstanceQuery.listPage(((pageNumber - 1) * pageSize), pageSize);
		List<EProcessInstance> epiList = new ArrayList<EProcessInstance>();
		ProcessDefinitionCache.setRepositoryService(repositoryService);
		for (ProcessInstance pi : list) {
			EProcessInstance epi = BeanMapper.map(pi, EProcessInstance.class);
			epiList.add(epi);
			epi.setActivityName(ProcessDefinitionCache.getActivityName(pi.getProcessDefinitionId(), pi.getActivityId()));
		}
		EasyuiGrid grid = new EasyuiGrid();
		grid.setRows(epiList);
		grid.setTotal((int) processInstanceQuery.count());
		String result = jsonMapper.toJson(grid);
		return result;
	}

	@RequestMapping("delete")
	@ResponseBody
	public String endProcessInstance(@RequestParam("processInstanceId") String processInstanceId) {
		runtimeService.deleteProcessInstance(processInstanceId, "删除流程实例");
		return ajaxMsg("流程实例删除成功", true, null);
	}

	/**
	 * 签收任务
	 */
	@RequestMapping(value = "/task/claim/{id}", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String claim(@PathVariable("id") String taskId, HttpSession session, RedirectAttributes redirectAttributes) {
		taskService.claim(taskId, BasicController.getCurrentUserId());
		return ajaxMsg("任务签收成功，请您及时办理", true, null);
	}

	/**
	 * 待办任务--Portlet
	 */
	@RequestMapping(value = "/task/todo/list", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String todoList(HttpSession session) throws Exception {
		List<ETask> eTaskList = new ArrayList<ETask>();
		// 已经签收的任务
		List<Task> todoList = taskService.createTaskQuery().taskAssignee(BasicController.getCurrentUserId()).active().list();
		for (Task task : todoList) {
			String processDefinitionId = task.getProcessDefinitionId();
			ProcessDefinition processDefinition = getProcessDefinition(processDefinitionId);

			ETask eTask = packageTaskInfo(task, processDefinition);
			eTask.setStatus(ETask.TODO);
			eTaskList.add(eTask);
		}
		EasyuiGrid grid = new EasyuiGrid();
		grid.setRows(eTaskList);
		grid.setTotal(eTaskList.size());
		String result = jsonMapper.toJson(grid);
		return result;
	}

	/**
	 * 待领任务--Portlet
	 */
	@RequestMapping(value = "/task/toclaim/list", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String toclaimList(HttpSession session) throws Exception {
		List<ETask> eTaskList = new ArrayList<ETask>();
		// 等待签收的任务
		List<String> roleNoList = BasicController.getCurrentUserRoleNoList();
		if (!Collections3.isEmpty(roleNoList)) {
			List<Task> toClaimList = taskService.createTaskQuery().taskCandidateGroupIn(roleNoList).active().orderByTaskCreateTime().desc()
					.list();
			for (Task task : toClaimList) {
				String processDefinitionId = task.getProcessDefinitionId();
				ProcessDefinition processDefinition = getProcessDefinition(processDefinitionId);
				ETask eTask = packageTaskInfo(task, processDefinition);
				eTask.setStatus(ETask.CLIAM);
				eTaskList.add(eTask);
			}
		}
		EasyuiGrid grid = new EasyuiGrid();
		grid.setRows(eTaskList);
		grid.setTotal(eTaskList.size());
		String result = jsonMapper.toJson(grid);
		return result;
	}

	/**
	 * 读取Task的表单
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/task/get-form/{taskId}")
	@ResponseBody
	public Map<String, Object> findTaskForm(@PathVariable("taskId") String taskId) throws Exception {
		Map<String, Object> result = new HashMap<String, Object>();
		TaskFormDataImpl taskFormData = (TaskFormDataImpl) formService.getTaskFormData(taskId);
		// 设置task为null，否则输出json的时候会报错
		taskFormData.setTask(null);
		result.put("taskFormData", taskFormData);
		/*
		 * 读取enum类型数据，用于下拉框
		 */
		List<FormProperty> formProperties = taskFormData.getFormProperties();
		for (FormProperty formProperty : formProperties) {
			Map<String, String> values = (Map<String, String>) formProperty.getType().getInformation("values");
			if (values != null) {
				for (Entry<String, String> enumEntry : values.entrySet()) {
					logger.debug("enum, key: {}, value: {}", enumEntry.getKey(), enumEntry.getValue());
				}
				result.put(formProperty.getId(), values);
			}
		}
		return result;
	}

	/**
	 * 提交task的并保存form
	 */
	@RequestMapping(value = "/task/complete/{taskId}", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String completeTask(@PathVariable("taskId") String taskId, HttpServletRequest request) {
		Map<String, String> formProperties = new HashMap<String, String>();

		// 从request中读取参数然后转换
		Map<String, String[]> parameterMap = request.getParameterMap();
		Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
		for (Entry<String, String[]> entry : entrySet) {
			String key = entry.getKey();
			// fp_的意思是form paremeter
			if (StringUtils.defaultString(key).startsWith("fp_")) {
				formProperties.put(key.split("_")[1], entry.getValue()[0]);
			}
		}

		logger.debug("start form parameters: {}", formProperties);
		try {
			identityService.setAuthenticatedUserId(BasicController.getCurrentUserId());
			formService.submitTaskFormData(taskId, formProperties);
			return ajaxMsg("任务完成：taskId=" + taskId, true, null);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			identityService.setAuthenticatedUserId(null);
		}
		return ajaxMsg("任务失败", false, null);
	}

	/**
	 * 流程实例的历史任务
	 */
	@RequestMapping(value = "/task/historicTaskInstance/{processInstanceId}", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String datagridHistoricTaskInstance(@PathVariable("processInstanceId") String processInstanceId) throws Exception {
		List<HistoricTaskInstance> historicTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
				.list();
		List<HistoricTaskInstance> result = new ArrayList<HistoricTaskInstance>();
		BeanMapper.copy(historicTasks, result);
		EasyuiGrid grid = new EasyuiGrid();
		grid.setRows(result);
		grid.setTotal(result.size());
		return jsonMapper.toJson(grid);
	}

	/**
	 * 流程实例的历史变量
	 */
	@RequestMapping(value = "/task/historicVariableInstance/{processInstanceId}", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String datagridHistoricVariableInstance(@PathVariable("processInstanceId") String processInstanceId) throws Exception {
		List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery()
				.processInstanceId(processInstanceId).list();
		EasyuiGrid grid = new EasyuiGrid();
		grid.setRows(historicVariableInstances);
		grid.setTotal(historicVariableInstances.size());
		String result = jsonMapper.toJson(grid);
		return result;
	}

	private ProcessDefinition getProcessDefinition(String processDefinitionId) {
		ProcessDefinition processDefinition = PROCESS_DEFINITION_CACHE.get(processDefinitionId);
		if (processDefinition == null) {
			processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
			PROCESS_DEFINITION_CACHE.put(processDefinitionId, processDefinition);
		}
		return processDefinition;
	}

	private ETask packageTaskInfo(Task task, ProcessDefinition processDefinition) {
		ETask eTask = new ETask();
		eTask.setId(task.getId());
		eTask.setName(task.getName());
		eTask.setCreateTime(task.getCreateTime());
		eTask.setPdname(processDefinition.getName());
		eTask.setPdversion(processDefinition.getVersion());
		eTask.setPid(task.getProcessInstanceId());
		return eTask;
	}
}
